home *** CD-ROM | disk | FTP | other *** search
-
- By now you will probably know how
- to start a verticalblanking interrupt. Here's how to do it.
-
- In $6c.L is the address where the computer will jump to
- each time the Vblank occurs. If you want to put your own routine
- (like a replay routine) in the Vblank interrupt, you just take the
- address in $6c, and save it somewhere (to jump back to when your
- routine is ready) and put the startaddress of your own routine in it.
-
- .. ...
- MOVE.L $6C,OLDINT+2 ; SAVE JUMP-BACK ADDRESS
- MOVE.L #INT,$6C ; OUR OWN ROUTINE
- ...
-
-
- INT: ....
- ....
- OLDINT: JMP $00000000 ; OLDINT= 'JMP'-OPCODE
- ; OLDINT+2 = JUMPBACK ADDR.
-
- There are addresses for all interrupts (like $6c). On the
- '!' page I sent last time are other addresses too. Now I have only
- used the Vblank and the Keyboardinterrupt. (this is $68) It occurs
- when you press a key AND when you release it again. Interpreting
- a pressed key is somewhat difficult. The code for the pressed key
- is found in $bfec01, but first you got to do some operations on it.
- Here's the routine:
-
- .. KEYINT: CLR.L D0
- MOVE.B $BFEC01,D0
- NOT.B D0
- ROR.B #1,D0 ; bit 8 is up/donw code
- 1) ANDI.W #$007F,D0 ; NOW, D0 = RAW KEYCODE
- ....
- OLDKEYINT:
- JMP $0000000 ; install as vblankint
-
- The code you get in D0 after these operations is what is called
- the RAW keycode. It's NOT an ascii value or something. Somewhere
- in the pack you'll find a table with these codes. As you'll see,
- ALL keys have a value, even the SHIFT and CTRL-keys.
- The line with '1)' kills the leftmost bit in D0.B, this bit is 0 if
- the key is currently PRESSED and 1 if it is RELEASED. To get the
- code in the table you have to compare only the other bits, so in line
- 1) this bit is killed. To know if the key is pressed or released, you
- have to check bit 8 before this line. It could be important to check
- because when you perform a printroutine each time you get a keyboard
- interrupt, you will get each pressed key 2 times on the screen (once
- when you press, once when you release)
-
-
- LIBRARIES
- ---------
-
- Now let's talk a bit about libraries and library-routines. You sure
- have heard that there are several interesting (and less interesting)
- routines stored in the libraries. Most important libraries are in
- ROM, others are on disk (in the libraries directory) To use routs
- of a lib, you must first open this library, in other words, you must
- get to know where the library is in memory (relative addressing,
- remember ?) If the lib is not in memory, it will be loaded from disk
- when you open it. There is a routine which is called 'OPENLIB', and
- it gives you the starting address of the library you opened. Other
- routines are located at a fixed place, relative to this starting
- address. You got some lists of the (standard) libraries from AmigaDos
- There are other libraries, like Explode Library, but they are not
- 'offcial' libraries, and I don't have lists of the routines in them.
- If you want, you can create your own libraries, but you'll have to
- find out yourself. Maybe you can learn me when you did. Anyway, let's
- go on. Most routines have some parameters. If you know something
- about C-language, it could be very simple to understand:
-
- result = function([parameter][...])
-
- General rule: only 1 result ! In Machinecode, this result is Always
- stored in register D0. The parameters differ from routine to rout.
- See lists in previous sending. For example: the routine OPEN in
- the dos-library. you'll find:
-
- -$001e -30 Open (name, accessmode)(d1,d2)
-
- Which means, routine OPEN is at ofset -$001e (or -30 decimal) in the
- doslib, and parameters are NAME in D1, and accessmode in D2. The
- result is in D0.
- As said, opening a library in fact means getting the startaddress.
- When you know that the function 'Openlib' is in a library itself,
- you could ask the question : how would you open THIS library ?
- GOOD QUESTION ! The answer is: You Don't Have to !! The startaddr
- of this library is known, you can find it in $4. (MOVE.L $4,A6
- will put the startaddress of the exec.library in A6, remember: it's
- the CONTENTS of $4 and not $4 that is the startaddress !)
- Once you got this address, you can call any routine in this library,
- among which is OpenLib, so now you can open the other libraries, like
- for example the doslib.
- Here's a complete source of how to open the Dos-library:
-
- .. opendoslib:
- move.l $4.w,a6 ; load execbase
- lea.l dosname,a1 ; parameter for openlib
- jsr -408(a6) ; execute routine openlib
- move.l d0,dosbase ; store result
- tst.l d0 ; something wrong ?
- beq error ; yep !
- rts ; nope !
-
- error: .... ; HELP, something wrong !
-
- dosname: dc.b "dos.library",0
- even
- dosbase: dc.l 0
-
- As said, D0 is the result of the operation. In most cases, if D0 is
- zero (tst.l d0), there was something wrong, like the library couldn't
- be opened, etc. However, when you can't open Doslib, not much can be
- done I'm afraid, and it won't happen anyway, so you don't have to
- check this really. But when you open a dozen of windows, it could
- happen that you run out of memory, and a D0=0 would tell you so.
- After your source is ready to RTS to CLI, you should always close
- opened libraries (except the EXEC, which in fact you didn't open)
- This is done as follows:
-
- .. Closedoslib:
- move.l $4.w,a6 ; load execbase
- move.l dosbase,a1 ; start of lib to close
- jsr -414(a6) ; close it
-
- 2 notes on this: move.l dosbase,a1 IS NOT THE SAME AS
- lea.l dosbase,a1 !!!
- You really need the VALUE IN dosbase and not the address #dosbase.
- (I say this coz I made this mistake often)
- 2nd note: MOVE.L $4.W,a6 notice the $4.W : this saves you 2
- bytes: address $4 is in the lowest 64K of memory, and so it can be
- addressed using only 1 word instead of 1 longword.
- move.l $4,a6 is assembled something like this: 3245 00000004
- move.l $4.w,a6 " " " : 3265 0004
- WOW AIN'T THAT SHOCKING !! WE SAVED 2 BYTES !!
- (and we wasted only 7 lines)
-
- Now here's some detailed descriptions of the parameters for the
- most commonly used DOSLIB routines, I can't tell'em all, 1) coz I
- haven't used them yet and I dunno, 2) coz there are too much of'em
- 3) coz I haven't got all day 4) coz you won't be using them neither.
-
- One very interesting routine is the EXECUTE. It makes it possible to
- run any file on disk (like a demo) straight from an assembler program
- (like a MENU or a LOADER...) Here's the routine, (ofcourse after
- opening the DOSLIB)
-
-
- .. EXECUTE_IT:
- ...
- move.l dosbase,a6 ; load dosbase
- move.l #command,d1 ; pointer to command in d1
- clr.l d2
- clr.l d3
- jsr -222(a6) ; execute
- move.l d0,returncode ; optional, not often used
- ...
-
- command: dc.b "df0:demo1",0 ; filename to execute
- even
-
- d2 and d3 are used to redirect input and output (just set to zero
- if you don't use them) (like "dir df0: > dirfile", d2 would be
- a pointer to "DIRFILE")
- When you wish to use 'execute' routine, the command RUN should be in
- the C: directory. If RUN isn't there, nothing will be executed...
- The result of the excute is a returncode, which the finished program
- gives back in d0. (You sometimes see badly written demos giving a
- returncode = xxxxx when they're finished, so now you know why: they
- forgot to clear D0 at the end. (This is only noticable when they're
- run from within a batchfile)) In advanced DOS-scripts, this is used
- to give results (like 'file not found') to other doscommands.
-
- .. OPEN_FILE:
- ...
- move.l dosbase,a6 ; load dosbase
- move.l #filename,d1 ; ptr to filename
- move.l #1005,d2 ; mode = read
- jsr -30(a6) ; open
- move.l d0,handle ; save result
- ...
-
- filename: dc.b "df0:boringfile",0
- even
- handle: dc.l 0
-
- You can open a file in 3 ways: read from it: mode = 1005
- write to it: mode = 1006, and read/write: mode = 1004
- in D0 you get the handle to that file, you need it for further
- operations.
-
- .. READING A FILE
-
- the description for this routine is:
-
- amount = Read (handle, buffer, length)
- d0 = -42 d1 d2 d3
-
- (This is a somewhat shorter notation, I'll use this in the next
- examples. One last time, I'll give you the source for this)
-
- ...
- move.l dosbase,a6
- move.l handle,d1 ; d1 = handle (value)
- move.l #buffer,d2 ; d2 = buffer (pointer to)
- move.l #length,d3 ; d3 = length (value)
- jsr -42(a6) ; Read
- move.l d0,.... ; optional
-
- handle: dc.l 0 ; filled by 'lock'
- length= xxxxx
- buffer: blk.b length,0
- even
-
- You can read more than one time, in fact you can read until you
- reach the end of the file.
- d0 is the amount of bytes read (amount <= length)
- d0 = 0 : end of file reached
- d0 = -1 : error (disk removed or something, I suppose)
-
- .. WRITING A FILE
-
- amount = Write (handle, buffer, length)
- d0 -48 d1 d2 d3
-
- same param's as in read
-
- .. SEEK
-
- move the file-pointer in a opened file
-
- Position = SEEK (handle, distance, mode)
- d0 -66 d1 d2 d3
-
- mode tells whether the distance is measured starting at the start
- of the file (mode = -1), or from the current position (mode = 0)
- or starting at the end (mode = 1)
- Distance then tells the offset from the defined position:
- Distance -20 with mode 1 puts the filepointer to 20 bytes from the
- end of the file etc.
-
- .. IOERR
-
- get the precise dos-error
-
- error = IOERR ()
- d0 -132
-
- Refer to DOS-manual for errorvalues & meanings: example
-
- 121: not executable ('file is not an object module')
- 221: disk full
- ...
-
-
- OK, so much for the most important dos-routines. Maybe you'll use
- some of these in a menu or a bootloader or something.
- As I know out of experience, it's best not to mess around with the
- interrupts/DMA when using DOS routines, coz there's much chance that
- it won't work/crash once in a while.
- The Readdir routine which is desacribed now, is causing me LOADS of
- trouble, it just won't work when I want it, and the weird thig is that
- it works sometimes. I HATE THAT ! I have to cancel all my current
- projects coz they all need these silly diskactivities and they just
- don't work together with my hardware-routines. (I told you before)
-
-
- ....
- move.l dosbase(pc),a6
- move.l #path,d1 ; name of directory
- moveq.l #-2,d2 ; read
- jsr -84(a6) ; 'lock'
- tst.l d0
- beq.s dir_error
- move.l d0,lock
-
- move.l lock(pc),d1
- move.l #fileinfo,d2 ; ptr to fileinfo block
- jsr -102(a6) ; 'examine'
- tst.l d0 ; fills up fileinfo with
- beq.s dir_error ; info about the directory
-
- dir_loop:
- move.l lock(pc),d1
- move.l #fileinfo,d2
- jsr -108(a6) ; 'examine next'
- tst.l d0 ; fills up fileinfo with
- beq dir_error ; info about files/subdirs
- bsr dir_printnames ; routine to print name
- bra.s dir_loop ; next, until d0 = 0
- dir_error:
- jsr -132(a6) ; IOERR check which error
- rts
-
- path: dc.b "df0:",0
- even
- lock: dc.l 0
- fileinfo: blk.b 260,0
-
-
- The routines 'examine' and 'exnext' will fill up a block of data
- (fileinfo) which has the following structure:
-
- offset: 0 drivenumber
- 4 type of entry (dir/file)
- 8 filename (108 bytes)
- 116 protection code
- 120 type of entry
- 124 size of file (bytes)
- 128 number of blocks
- 132 days \
- 136 minutes | creation time
- 140 ticks /
- 144 comment (116 bytes filenote)
- 260
-
- As I said, I've still got major problems with this thing, and I
- haven't been able to test all of it. For example I think that the
- name of a directory starts at ofset 10 instead of ofset 8, but I'm
- not sure. This book I got isn't complete by a 100 lightyears !
- Above all, in the whole book are several 'typing errors' as it is
- translated from German. Ow boy.
-
- Anyway, now we've seen nearly all of the DOS-things, it's time to
- go to a lower level: the TRACKDISK device. Devices are something
- between hardware and library-programming. There are several devices,
- like 'trackdisk', 'printer', 'console',...
- They use more 'sophisticated' stuff like nodes and messages to
- communicate between other tasks, and it's this stuff that I'm trying
- to master now (but it's not working yet) Anyway, I've done some
- experiments with trackdisk already. here's an attempt:
-
- doio: move.l $4.w,a6 ;
- sub.l a1,a1 ;
- jsr -294(a6) ; findtask (buerk)
- move.l d0,readreply+$10 ;
- lea.l readreply,a1 ;
- jsr -354(a6) ; addport (buerk)
- lea.l diskio,a1 ;
- move.l #0,d0 ; drive: df0:
- clr.l d1 ; no flags (?)
- lea.l devicename,a0 ;
- jsr -444(a6) ; opendevice !!
- tst.l d0
- bne.s trerror
-
- lea.l diskio,a1
- move.l #readreply,14(a1) ; reply port (buerk)
- move.w #2,28(a1) ; instruction : read
- move.l #diskbuff,40(a1) ; ptr to buffer
- move.l #.....,36(a1) ; amount of bytes to read
- move.l #.....,44(a1) ; ofset on disk
- jsr -456(a6) ; do-I/O
-
- lea.l diskio,a1
- move.w #9,28(a1)
- move.l #0,36(a1)
- jsr -456(a6) ;motorout
- lea.l readreply,a1
- jsr -360(a6) ;remport (buerk)
- lea.l diskio,a1
- jsr -450(a6) ;closedev
- trerror:rts
-
- diskio: blk.l 20,0
- readreply: blk.l 8,0
- devicename: dc.b "trackdisk.device",0
- even
- diskerror: dc.b 0
- even
- diskbuff: dc.l 0
-
-
- The routines with 'Buerk' are not really clear to me. They refer to
- a structure that is used by the device, it looks like this:
-
- ofset: 0 ... ; typical node structure,
- ; don't bother
- 14 pointer to replyport (task communication)
- 18 length of structure (don't bother)
-
- 20 pointer to devicenode (don't bother)
- 24 unit (don't bother) (?)
- 28 command: These are (some of) the possible commands
- for the devices:
- read: #2
- write: #3
- update: #4 (?)
- clear: #5 (?)
- motorout: #9 (only for trackdisk)
- 30 flags (don't bother) (?)
- 31 error (example: 28 = write prot)
- (didn't work when I tried or I did smth wrong)
- 32 actual number of read/written bytes
- 36 number of bytes to send/recieve
- example: number = 2*512: 2 blocks to transfer
- 40 ptr to memory
- 44 offset (amount of bytes behind 1st byte on disk)
- example: offset = 880*512: read/write at block 880
- there are 22 blocks/track
-
- Maybe it's now the right time to tell you the relation between the
- different 'levels' of ROM-routines in the AMiga. At the highest
- level you have the DOS-routines, like read, write, execute. As you
- can imagine, there's a whole lot of programming behind these commands
- as they handle trackread, updating of directory, detecting of errors
- directory/file handling, checksums, free space etc. The next level
- is the TRACKDISK. Dos-routines use the trackdisk-device, this is not
- as sophisticated as DOS, as it only reads/writes tracks, there's
- nothing like file/directory/checksums at this level. It's therefor a
- whole bit faster. (especially coz you can reduce the read/write-head
- movement to a minimum by putting programs on consecutive tracks.
- Most megademos use trackdisk, you can recognise it by a 'tack-tack-
- tack' with constant speed. The lowest level is the DMA, like we did
- when using blitter, for example. You can just as well put values in
- special registers used for diskdrive, and get some things read
- from disk. This is the most complicated way of working, and also
- the fastest.Working this way you can chenge the speed of the drive-
- head (and make the funny noise you sometimes with some hardware
- loader (njiiii-njiiii-retetetete / ow boy it's melting !!)
- I've heard that you can kill your drive by messing too much with the
- drive-hardware registers, but anyway, sounds fascinating. You can also
- read tracks behind 79 with the hardware-method, which could make head
- trying to read on the plastic of your disks. (aaargh)
- These same 3 levels can be found in other parts of the amiga, but
- coz of a lack of decent documentation, I haven't been able to
- experiment on them. Until then we will go on messing with the
- hardware and the DMA.
-
-
- NOW. I guess you know most thing you need to know now, for more
- detailled things you can now refer to manual, (most manuals forget
- that there are beginners too in this world, they just are too
- difficult to start with)
-